package com.atsmart.app.utils;


// The SnapOut Preview Algorithm functions process on either byte or int buffers.
// byte buffers are in the bmp file format
// int buffers are in Image raw format
// The functions process1, process2, and process3 all implement the same
// algorithm on different combinations of buffers.
// Each function has an input fg buffer, and input bg buffer,
// and an output result buffer.  Some of the functions share a single
// input/output buffer for "in-place" processing.

// process1: (in-place on fg)
//   fg     (in)  byte[] imgBmp_byt
//   bg     (in)  int[]  bg_dat
//   result (out) byte[] imgBmp_byt
//
// process2:
//   fg     (in)  byte[] imgBmp_byt
//   bg     (in)  int[]  bg_dat
//   result (out) int[]  result_dat
//
// process3: (in-place on fg)
//   fg     (in)  int[]  result_dat
//   bg     (in)  int[]  bg_dat
//   result (out) int[]  result_dat

public class SnapPreview implements AbstractPreviewProvider {

	// 1024/204.8 = 5.00
	// 1024/192.0 = 5.33
	// 1024/170.6 = 6.00
	static final private int T = 192; // 270;

	static final private int bmpHeadSz = 54;

	private int[] getBackingColor_byt(byte[] imgBmp_byt, int w, int h, int d) {
		final int backingSz = 4;
		final int backingSz2 = backingSz * backingSz;
		final int xBackingOff = 0 + 5;
		final int yBackingOff = h - 5 - backingSz;
		final int rowBytes = w * d;
		final boolean showBackingLocation = false;

		int i, j;
		int fr = 0, fg = 0, fb = 0;
		int rowOff = SnapPreview.bmpHeadSz + yBackingOff * rowBytes;
		for(j = yBackingOff; j < yBackingOff + backingSz; j++) {
			int pixOff = rowOff + xBackingOff * d;
			for(i = xBackingOff; i < xBackingOff + backingSz; i++) {
				// fr += (int)imgBmp_byt[pixOff + 2];
				// fg += (int)imgBmp_byt[pixOff + 1];
				// fb += (int)imgBmp_byt[pixOff + 0];
				fr += (0x000000FF & imgBmp_byt[pixOff + 2]);
				fg += (0x000000FF & imgBmp_byt[pixOff + 1]);
				fb += (0x000000FF & imgBmp_byt[pixOff + 0]);

				if(showBackingLocation) {
					imgBmp_byt[pixOff + 2] = 0x00; // force backing color area visual indicator
					imgBmp_byt[pixOff + 1] = -0x80;
					imgBmp_byt[pixOff + 0] = 0x7f;
				}

				pixOff += d; // advance to next pixel
			}
			rowOff += rowBytes; // advance to next row
		}
		int[] backing = new int[3];
		backing[0] = fr / backingSz2;
		backing[1] = fg / backingSz2;
		backing[2] = fb / backingSz2;
		return backing;
	}

	private int[] getBackingColor_int(int[] dat, int w, int h) {
		final int backingSz = 4;
		final int backingSz2 = backingSz * backingSz;
		final int xBackingOff = 0 + 5;
		final int yBackingOff = 0 + 5; // h - 5 - backingSz;
		final boolean showBackingLocation = false;

		int i, j;
		int fr = 0, fg = 0, fb = 0;
		int bRowOff = yBackingOff * w;
		for(j = yBackingOff; j < yBackingOff + backingSz; j++) {
			int bPixOff = bRowOff + xBackingOff;
			for(i = xBackingOff; i < xBackingOff + backingSz; i++) {
				fr += ((dat[bPixOff] & 0x00ff0000) >> 16);
				fg += ((dat[bPixOff] & 0x0000ff00) >> 8);
				fb += (dat[bPixOff] & 0x000000ff);

				if(showBackingLocation) {
					dat[bPixOff] = 0x0000ff00; // force backing color area visual indicator
				}

				bPixOff += 1; // advance to next pixel
			}
			bRowOff += w; // advance to next row
		}

		int[] backing = new int[3];
		backing[0] = fr / backingSz2;
		backing[1] = fg / backingSz2;
		backing[2] = fb / backingSz2;
		return backing;
	}

	// Normal version
	public void process1(byte[] imgBmp_byt, int[] bg_dat, int w, int h) {
		// TODO: read w, h, d, rowBytes, and header size from bmp header
		final int d = 3;
		final int rowBytes = w * d;

		int i, j;
		int rowOff;
		int bRowOff;

		// foreground image color
		int fr, fg, fb;

		// background image color
		int ba = 0, br, bg, bb;

		int[] backing = getBackingColor_byt(imgBmp_byt, w, h, d);

		// process image
		rowOff = SnapPreview.bmpHeadSz;
		// bRowOff = 0;
		bRowOff = (h - 1) * w; // background image is upside-down
		for(j = 0; j < h; j++) {
			int pixOff = rowOff;
			int bPixOff = bRowOff;
			for(i = 0; i < w; i++) {
				final int dat = (bg_dat == null) ? 0xFF3264C8 : bg_dat[bPixOff]; // Ultimatte blue
				// final int dat = (bg_dat == null) ? 0xFF404040 : bg_dat[bPixOff]; // gray
				// final int dat = bg_dat[bPixOff]; // gray

				ba = ((dat & 0xff000000) >> 24);
				// required because java so doesn't provide unsigned types
				if(ba < 0) {
					ba += 256;
				}

				br = ((dat & 0x00ff0000) >> 16);
				bg = ((dat & 0x0000ff00) >> 8);
				bb = (dat & 0x000000ff);

	            if(ba > 64) { // arbitrary threshold
					// not Sandwich top-layer, use preview algorithm

					// fr = (int)imgBmp_byt[pixOff + 2];
					// fg = (int)imgBmp_byt[pixOff + 1];
					// fb = (int)imgBmp_byt[pixOff + 0];
					fr = (0x000000FF & imgBmp_byt[pixOff + 2]);
					fg = (0x000000FF & imgBmp_byt[pixOff + 1]);
					fb = (0x000000FF & imgBmp_byt[pixOff + 0]);

					// int dist = SnapUtil.abs(backing[0] - fr) +
					//            SnapUtil.abs(backing[1] - fg) +
					//            SnapUtil.abs(backing[2] - fb);

					// remove function call (speed optimization)
					int dist = ((backing[0] > fr) ? (backing[0] - fr) : (fr - backing[0])) +
					           ((backing[1] > fg) ? (backing[1] - fg) : (fg - backing[1])) +
					           ((backing[2] > fb) ? (backing[2] - fb) : (fb - backing[2]));

					// int m = (T < dist) ? 0 : (T - dist) * 1024 / T;

					// replace *1024 with shift(10) (speed optimization)
					// int m = (T < dist) ? 0 : ((T - dist) << 10) / T;

					// replace *1024/192 with *5 (speed optimization)
					int m = (T < dist) ? 0 : (T - dist) * 5;

		            // int pr = fr * 1024 - m * backing[0]; if(pr < 0) pr = 0;
		            // int pg = fg * 1024 - m * backing[1]; if(pg < 0) pg = 0;
		            // int pb = fb * 1024 - m * backing[2]; if(pb < 0) pb = 0;

					// replace *1024 with shift(10) (speed optimization)
		            int pr = (fr << 10) - m * backing[0]; if(pr < 0) pr = 0;
		            int pg = (fg << 10) - m * backing[1]; if(pg < 0) pg = 0;
		            int pb = (fb << 10) - m * backing[2]; if(pb < 0) pb = 0;

		            int cr = pr + m * br;
		            int cg = pg + m * bg;
		            int cb = pb + m * bb;

		            // write composite in-place into background
		            // 255 * 1024 = 261120
		            // imgBmp_byt[pixOff + 2] = (cr > 261120) ? (byte)255 : (byte)(cr / 1024);
		            // imgBmp_byt[pixOff + 1] = (cg > 261120) ? (byte)255 : (byte)(cg / 1024);
		            // imgBmp_byt[pixOff + 0] = (cb > 261120) ? (byte)255 : (byte)(cb / 1024);

					// replace /1024 with shift(-10) (speed optimization)
		            imgBmp_byt[pixOff + 2] = (cr > 261120) ? (byte)255 : (byte)(cr >> 10);
		            imgBmp_byt[pixOff + 1] = (cg > 261120) ? (byte)255 : (byte)(cg >> 10);
		            imgBmp_byt[pixOff + 0] = (cb > 261120) ? (byte)255 : (byte)(cb >> 10);
	            } else {
					// sandwich top-layer, use 100% pass-thru background image
					imgBmp_byt[pixOff + 2] = (byte)br;
					imgBmp_byt[pixOff + 1] = (byte)bg;
					imgBmp_byt[pixOff + 0] = (byte)bb;
				}

				pixOff += d; // advance foreground to next pixel
				bPixOff += 1; // advance background to next pixel
			}
			rowOff += rowBytes; // advance foreground to next row

			// advance background to next row
			// bRowOff += w;
			bRowOff -= w; // background image is upside-down
		}
	}

	// Ghost version
	public void process1(byte[] imgBmp_byt, int[] bg_dat, int[] ex_dat, int w, int h, int percent) {
		if(ex_dat == null || percent <= 0) {
			process1(imgBmp_byt, bg_dat, w, h);
			return;
		}

		// TODO: read w, h, d, rowBytes, and header size from bmp header
		final int d = 3;
		final int rowBytes = w * d;

		int i, j;
		int rowOff;
		int bRowOff;

		// foreground image color
		int fr, fg, fb;

		// background image color
		int ba = 0, br, bg, bb;

		// example image color
		int er, eg, eb;

		int[] backing = getBackingColor_byt(imgBmp_byt, w, h, d);

		final int percentInv = 100 - percent;

		// process image
		rowOff = SnapPreview.bmpHeadSz;
		// bRowOff = 0;
		bRowOff = (h - 1) * w; // background image is upside-down
		for(j = 0; j < h; j++) {
			int pixOff = rowOff;
			int bPixOff = bRowOff;
			for(i = 0; i < w; i++) {
				// read example image pixel
				final int ex = ex_dat[bPixOff];
				er = ((ex & 0x00ff0000) >> 16);
				eg = ((ex & 0x0000ff00) >> 8);
				eb = (ex & 0x000000ff);

				if(percent < 100) {

					// read background image pixel
					final int dat = (bg_dat == null) ? 0xFF3264C8 : bg_dat[bPixOff]; // Ultimatte blue
					// final int dat = (bg_dat == null) ? 0xFF404040 : bg_dat[bPixOff]; // gray
					// final int dat = bg_dat[bPixOff]; // gray

					ba = ((dat & 0xff000000) >> 24);
					// required because java so doesn't provide unsigned types
					if(ba < 0) {
						ba += 256;
					}

					br = ((dat & 0x00ff0000) >> 16);
					bg = ((dat & 0x0000ff00) >> 8);
					bb = (dat & 0x000000ff);

		            if(ba > 64) { // arbitrary threshold
						// not Sandwich top-layer, use preview algorithm

						// fr = (int)imgBmp_byt[pixOff + 2];
						// fg = (int)imgBmp_byt[pixOff + 1];
						// fb = (int)imgBmp_byt[pixOff + 0];
						fr = (0x000000FF & imgBmp_byt[pixOff + 2]);
						fg = (0x000000FF & imgBmp_byt[pixOff + 1]);
						fb = (0x000000FF & imgBmp_byt[pixOff + 0]);

						// int dist = SnapUtil.abs(backing[0] - fr) +
						//            SnapUtil.abs(backing[1] - fg) +
						//            SnapUtil.abs(backing[2] - fb);

						// remove function call (speed optimization)
						int dist = ((backing[0] > fr) ? (backing[0] - fr) : (fr - backing[0])) +
						           ((backing[1] > fg) ? (backing[1] - fg) : (fg - backing[1])) +
						           ((backing[2] > fb) ? (backing[2] - fb) : (fb - backing[2]));

						// int m = (T < dist) ? 0 : (T - dist) * 1024 / T;

						// replace *1024 with shift(10) (speed optimization)
						// int m = (T < dist) ? 0 : ((T - dist) << 10) / T;

						// replace *1024/192 with *5 (speed optimization)
						int m = (T < dist) ? 0 : (T - dist) * 5;

			            // int pr = fr * 1024 - m * backing[0]; if(pr < 0) pr = 0;
			            // int pg = fg * 1024 - m * backing[1]; if(pg < 0) pg = 0;
			            // int pb = fb * 1024 - m * backing[2]; if(pb < 0) pb = 0;

						// replace *1024 with shift(10) (speed optimization)
			            int pr = (fr << 10) - m * backing[0]; if(pr < 0) pr = 0;
			            int pg = (fg << 10) - m * backing[1]; if(pg < 0) pg = 0;
			            int pb = (fb << 10) - m * backing[2]; if(pb < 0) pb = 0;

			            int cr = pr + m * br;
			            int cg = pg + m * bg;
			            int cb = pb + m * bb;

			            // write composite in-place into background
			            // 255 * 1024 = 261120
			            // imgBmp_byt[pixOff + 2] = (cr > 261120) ? (byte)255 : (byte)(cr / 1024);
			            // imgBmp_byt[pixOff + 1] = (cg > 261120) ? (byte)255 : (byte)(cg / 1024);
			            // imgBmp_byt[pixOff + 0] = (cb > 261120) ? (byte)255 : (byte)(cb / 1024);

						// replace /1024 with shift(-10) (speed optimization)
			            br = (cr > 261120) ? 255 : (cr >> 10);
			            bg = (cg > 261120) ? 255 : (cg >> 10);
			            bb = (cb > 261120) ? 255 : (cb >> 10);
		            } else {
						// sandwich top-layer, use 100% pass-thru background image
						// imgBmp_byt[pixOff + 2] = (byte)br;
						// imgBmp_byt[pixOff + 1] = (byte)bg;
						// imgBmp_byt[pixOff + 0] = (byte)bb;
					}

		            // mix calculated pixel value with example image pixel
					br = (percentInv * br + percent * er) / 100;
					bg = (percentInv * bg + percent * eg) / 100;
					bb = (percentInv * bb + percent * eb) / 100;
				} else {
					// example 100%
					br = er; bg = eg; bb = eb;
				}
				imgBmp_byt[pixOff + 2] = (byte)br;
				imgBmp_byt[pixOff + 1] = (byte)bg;
				imgBmp_byt[pixOff + 0] = (byte)bb;

				pixOff += d; // advance foreground to next pixel
				bPixOff += 1; // advance background to next pixel
			}
			rowOff += rowBytes; // advance foreground to next row

			// advance background to next row
			// bRowOff += w;
			bRowOff -= w; // background image is upside-down
		}
	}

	// Normal version
	public void process2(byte[] imgBmp_byt, int[] bg_dat, int[] result_dat, int w, int h) {
		// TODO: read w, h, d, rowBytes, and header size from bmp header
		final int d = 3;
		final int rowBytes = w * d;

		int i, j;
		int rowOff;
		int bRowOff;

		// foreground image color
		int fr, fg, fb;

		// background image color
		int ba = 0, br = 0, bg = 0, bb = 0;

		int[] backing = getBackingColor_byt(imgBmp_byt, w, h, d);

		// process image
		rowOff = SnapPreview.bmpHeadSz;
		// bRowOff = 0;
		bRowOff = (h - 1) * w; // background image is upside-down

		for(j = 0; j < h; j++) {
			int pixOff = rowOff;
			int bPixOff = bRowOff;

			for(i = 0; i < w; i++) {
				/*
				if(bPixOff < 0 || bPixOff >= SnapOut.liveSize) {
					SnapError.log("SP.p2", "illegal bPixOff " + bPixOff + "(" + i + "," + j + ")");
					break;
				}
				*/
				final int dat = (bg_dat == null) ? 0xFF3264C8 : bg_dat[bPixOff]; // Ultimatte blue
				// final int dat = (bg_dat == null) ? 0xFF404040 : bg_dat[bPixOff]; // gray
				// final int dat = bg_dat[bPixOff];

				ba = ((dat & 0xff000000) >> 24);
				// required because java so doesn't provide unsigned types
				if(ba < 0) {
					ba += 256;
				}

				br = ((dat & 0x00ff0000) >> 16);
				bg = ((dat & 0x0000ff00) >> 8);
				bb = (dat & 0x000000ff);

	            if(ba > 64) { // arbitrary threshold
					// not Sandwich top-layer, use preview algorithm

					// fr = (int)imgBmp_byt[pixOff + 2];
					// fg = (int)imgBmp_byt[pixOff + 1];
					// fb = (int)imgBmp_byt[pixOff + 0];
					fr = (0x000000FF & imgBmp_byt[pixOff + 2]);
					fg = (0x000000FF & imgBmp_byt[pixOff + 1]);
					fb = (0x000000FF & imgBmp_byt[pixOff + 0]);

					// int dist = SnapUtil.abs(backing[0] - fr) +
					//            SnapUtil.abs(backing[1] - fg) +
					//            SnapUtil.abs(backing[2] - fb);

					// remove function call (speed optimization)
					int dist = ((backing[0] > fr) ? (backing[0] - fr) : (fr - backing[0])) +
					           ((backing[1] > fg) ? (backing[1] - fg) : (fg - backing[1])) +
					           ((backing[2] > fb) ? (backing[2] - fb) : (fb - backing[2]));

					// int m = (T < dist) ? 0 : (T - dist) * 1024 / T;

					// replace *1024 with shift(10) (speed optimization)
					// int m = (T < dist) ? 0 : ((T - dist) << 10) / T;

					// replace *1024/192 with *5 (speed optimization)
					int m = (T < dist) ? 0 : (T - dist) * 5;

		            // int pr = fr * 1024 - m * backing[0]; if(pr < 0) pr = 0;
		            // int pg = fg * 1024 - m * backing[1]; if(pg < 0) pg = 0;
		            // int pb = fb * 1024 - m * backing[2]; if(pb < 0) pb = 0;

					// replace *1024 with shift(10) (speed optimization)
		            int pr = (fr << 10) - m * backing[0]; if(pr < 0) pr = 0;
		            int pg = (fg << 10) - m * backing[1]; if(pg < 0) pg = 0;
		            int pb = (fb << 10) - m * backing[2]; if(pb < 0) pb = 0;

		            int cr = pr + m * br;
		            int cg = pg + m * bg;
		            int cb = pb + m * bb;

		            // write composite in-place into background
		            // 255 * 1024 = 261120
		            // imgBmp_byt[pixOff + 2] = (cr > 261120) ? (byte)255 : (byte)(cr / 1024);
		            // imgBmp_byt[pixOff + 1] = (cg > 261120) ? (byte)255 : (byte)(cg / 1024);
		            // imgBmp_byt[pixOff + 0] = (cb > 261120) ? (byte)255 : (byte)(cb / 1024);

					// replace /1024 with shift(-10) (speed optimization)
		            // imgBmp_byt[pixOff + 2] = (cr > 261120) ? (byte)255 : (byte)(cr >> 10);
		            // imgBmp_byt[pixOff + 1] = (cg > 261120) ? (byte)255 : (byte)(cg >> 10);
		            // imgBmp_byt[pixOff + 0] = (cb > 261120) ? (byte)255 : (byte)(cb >> 10);

					// replace /1024 with shift(-10) (speed optimization)
		            br = (cr > 261120) ? 255 : (cr >> 10);
		            bg = (cg > 261120) ? 255 : (cg >> 10);
		            bb = (cb > 261120) ? 255 : (cb >> 10);
	            } else {
					// sandwich top-layer, use 100% pass-thru background image
					// imgBmp_byt[pixOff + 2] = (byte)br;
					// imgBmp_byt[pixOff + 1] = (byte)bg;
					// imgBmp_byt[pixOff + 0] = (byte)bb;
	            }
				result_dat[bPixOff] = (br << 16) + (bg << 8) + bb;

				pixOff += d; // advance foreground to next pixel
				bPixOff += 1; // advance background to next pixel
			}
			rowOff += rowBytes; // advance foreground to next row

			// advance background to next row
			// bRowOff += w;
			bRowOff -= w; // background image is upside-down
		}
	}

	// Ghost version
	public void process2(byte[] imgBmp_byt, int[] bg_dat, int[] ex_dat, int[] result_dat, int w, int h, int percent) {
		if(ex_dat == null || percent <= 0) {
			process2(imgBmp_byt, bg_dat, result_dat, w, h);
			return;
		}

		// TODO: read w, h, d, rowBytes, and header size from bmp header
		final int d = 3;
		final int rowBytes = w * d;

		int i, j;
		int rowOff;
		int bRowOff;

		// foreground image color
		int fr, fg, fb;

		// background image color
		int ba = 0, br = 0, bg = 0, bb = 0;

		// example image color
		int er, eg, eb;

		int[] backing = getBackingColor_byt(imgBmp_byt, w, h, d);

		final int percentInv = 100 - percent;

		// process image
		rowOff = SnapPreview.bmpHeadSz;
		// bRowOff = 0;
		bRowOff = (h - 1) * w; // background image is upside-down

		for(j = 0; j < h; j++) {
			int pixOff = rowOff;
			int bPixOff = bRowOff;

			for(i = 0; i < w; i++) {
				/*
				if(bPixOff < 0 || bPixOff >= SnapOut.liveSize) {
					SnapError.log("SP.p2", "illegal bPixOff " + bPixOff + "(" + i + "," + j + ")");
					break;
				}
				*/

				// read example image pixel
				final int ex = ex_dat[bPixOff];
				er = ((ex & 0x00ff0000) >> 16);
				eg = ((ex & 0x0000ff00) >> 8);
				eb = (ex & 0x000000ff);

				if(percent < 100) {

					// read background image pixel
					final int dat = (bg_dat == null) ? 0xFF3264C8 : bg_dat[bPixOff]; // Ultimatte blue
					// final int dat = (bg_dat == null) ? 0xFF404040 : bg_dat[bPixOff]; // gray
					// final int dat = bg_dat[bPixOff];

					ba = ((dat & 0xff000000) >> 24);
					// required because java so doesn't provide unsigned types
					if(ba < 0) {
						ba += 256;
					}

					br = ((dat & 0x00ff0000) >> 16);
					bg = ((dat & 0x0000ff00) >> 8);
					bb = (dat & 0x000000ff);

		            if(ba > 64) { // arbitrary threshold
						// not Sandwich top-layer, use preview algorithm

						// fr = (int)imgBmp_byt[pixOff + 2];
						// fg = (int)imgBmp_byt[pixOff + 1];
						// fb = (int)imgBmp_byt[pixOff + 0];
						fr = (0x000000FF & imgBmp_byt[pixOff + 2]);
						fg = (0x000000FF & imgBmp_byt[pixOff + 1]);
						fb = (0x000000FF & imgBmp_byt[pixOff + 0]);

						// int dist = SnapUtil.abs(backing[0] - fr) +
						//            SnapUtil.abs(backing[1] - fg) +
						//            SnapUtil.abs(backing[2] - fb);

						// remove function call (speed optimization)
						int dist = ((backing[0] > fr) ? (backing[0] - fr) : (fr - backing[0])) +
						           ((backing[1] > fg) ? (backing[1] - fg) : (fg - backing[1])) +
						           ((backing[2] > fb) ? (backing[2] - fb) : (fb - backing[2]));

						// int m = (T < dist) ? 0 : (T - dist) * 1024 / T;

						// replace *1024 with shift(10) (speed optimization)
						// int m = (T < dist) ? 0 : ((T - dist) << 10) / T;

						// replace *1024/192 with *5 (speed optimization)
						int m = (T < dist) ? 0 : (T - dist) * 5;

			            // int pr = fr * 1024 - m * backing[0]; if(pr < 0) pr = 0;
			            // int pg = fg * 1024 - m * backing[1]; if(pg < 0) pg = 0;
			            // int pb = fb * 1024 - m * backing[2]; if(pb < 0) pb = 0;

						// replace *1024 with shift(10) (speed optimization)
			            int pr = (fr << 10) - m * backing[0]; if(pr < 0) pr = 0;
			            int pg = (fg << 10) - m * backing[1]; if(pg < 0) pg = 0;
			            int pb = (fb << 10) - m * backing[2]; if(pb < 0) pb = 0;

			            int cr = pr + m * br;
			            int cg = pg + m * bg;
			            int cb = pb + m * bb;

			            // write composite in-place into background
			            // 255 * 1024 = 261120
			            // imgBmp_byt[pixOff + 2] = (cr > 261120) ? (byte)255 : (byte)(cr / 1024);
			            // imgBmp_byt[pixOff + 1] = (cg > 261120) ? (byte)255 : (byte)(cg / 1024);
			            // imgBmp_byt[pixOff + 0] = (cb > 261120) ? (byte)255 : (byte)(cb / 1024);

						// replace /1024 with shift(-10) (speed optimization)
			            // imgBmp_byt[pixOff + 2] = (cr > 261120) ? (byte)255 : (byte)(cr >> 10);
			            // imgBmp_byt[pixOff + 1] = (cg > 261120) ? (byte)255 : (byte)(cg >> 10);
			            // imgBmp_byt[pixOff + 0] = (cb > 261120) ? (byte)255 : (byte)(cb >> 10);

						// replace /1024 with shift(-10) (speed optimization)
			            br = (cr > 261120) ? 255 : (cr >> 10);
			            bg = (cg > 261120) ? 255 : (cg >> 10);
			            bb = (cb > 261120) ? 255 : (cb >> 10);
		            } else {
						// sandwich top-layer, use 100% pass-thru background image
						// imgBmp_byt[pixOff + 2] = (byte)br;
						// imgBmp_byt[pixOff + 1] = (byte)bg;
						// imgBmp_byt[pixOff + 0] = (byte)bb;
		            }

		            // mix calculated pixel value with example image pixel
					br = (percentInv * br + percent * er) / 100;
					bg = (percentInv * bg + percent * eg) / 100;
					bb = (percentInv * bb + percent * eb) / 100;
				} else {
					// example 100%
					br = er; bg = eg; bb = eb;
				}
				result_dat[bPixOff] = (br << 16) + (bg << 8) + bb;

				pixOff += d; // advance foreground to next pixel
				bPixOff += 1; // advance background to next pixel
			}
			rowOff += rowBytes; // advance foreground to next row

			// advance background to next row
			// bRowOff += w;
			bRowOff -= w; // background image is upside-down
		}
	}

	// Normal version
	public void process3(int[] bg_dat, int[] result_dat, int w, int h) {
		// TODO: read w, h, d, rowBytes, and header size from bmp header
		// int d = 3;
		// int rowBytes = w * d;

		int i, j;
		// int rowOff;
		int bRowOff;

		// foreground image color
		int fr, fg, fb;

		// background image color
		int ba = 0, br, bg, bb;

		int[] backing = getBackingColor_int(result_dat, w, h);

		// process image
		// rowOff = SnapOut.bmpHeadSz;
		// bRowOff = 0;
		bRowOff = (h - 1) * w; // background image is upside-down
		for(j = 0; j < h; j++) {
			// int pixOff = rowOff;
			int bPixOff = bRowOff;
			for(i = 0; i < w; i++) {
				final int dat = (bg_dat == null) ? 0xFF3264C8 : bg_dat[bPixOff]; // Ultimatte blue
				// final int dat = (bg_dat == null) ? 0xFF404040 : bg_dat[bPixOff]; // gray
				// final int dat = bg_dat[bPixOff]; // gray

				ba = ((dat & 0xff000000) >> 24);
				// required because java so doesn't provide unsigned types
				if(ba < 0) {
					ba += 256;
				}

				br = ((dat & 0x00ff0000) >> 16);
				bg = ((dat & 0x0000ff00) >> 8);
				bb = (dat & 0x000000ff);

	            if(ba > 64) { // arbitrary threshold
					// not Sandwich top-layer, use preview algorithm

					fr = ((result_dat[bPixOff] & 0x00ff0000) >> 16);
					fg = ((result_dat[bPixOff] & 0x0000ff00) >> 8);
					fb = (result_dat[bPixOff] & 0x000000ff);

					// int dist = SnapUtil.abs(backing[0] - fr) +
					//            SnapUtil.abs(backing[1] - fg) +
					//            SnapUtil.abs(backing[2] - fb);

					// remove function call (speed optimization)
					int dist = ((backing[0] > fr) ? (backing[0] - fr) : (fr - backing[0])) +
					           ((backing[1] > fg) ? (backing[1] - fg) : (fg - backing[1])) +
					           ((backing[2] > fb) ? (backing[2] - fb) : (fb - backing[2]));

					// int m = (T < dist) ? 0 : (T - dist) * 1024 / T;

					// replace *1024 with shift(10) (speed optimization)
					// int m = (T < dist) ? 0 : ((T - dist) << 10) / T;

					// replace *1024/192 with *5 (speed optimization)
					int m = (T < dist) ? 0 : (T - dist) * 5;

		            // int pr = fr * 1024 - m * backing[0]; if(pr < 0) pr = 0;
		            // int pg = fg * 1024 - m * backing[1]; if(pg < 0) pg = 0;
		            // int pb = fb * 1024 - m * backing[2]; if(pb < 0) pb = 0;

					// replace *1024 with shift(10) (speed optimization)
		            int pr = (fr << 10) - m * backing[0]; if(pr < 0) pr = 0;
		            int pg = (fg << 10) - m * backing[1]; if(pg < 0) pg = 0;
		            int pb = (fb << 10) - m * backing[2]; if(pb < 0) pb = 0;

		            int cr = pr + m * br;
		            int cg = pg + m * bg;
		            int cb = pb + m * bb;

		            // write composite in-place into background
		            // 255 * 1024 = 261120
		            // imgBmp_byt[pixOff + 2] = (cr > 261120) ? (byte)255 : (byte)(cr / 1024);
		            // imgBmp_byt[pixOff + 1] = (cg > 261120) ? (byte)255 : (byte)(cg / 1024);
		            // imgBmp_byt[pixOff + 0] = (cb > 261120) ? (byte)255 : (byte)(cb / 1024);

					// replace /1024 with shift(-10) (speed optimization)
		            // imgBmp_byt[pixOff + 2] = (cr > 261120) ? (byte)255 : (byte)(cr >> 10);
		            // imgBmp_byt[pixOff + 1] = (cg > 261120) ? (byte)255 : (byte)(cg >> 10);
		            // imgBmp_byt[pixOff + 0] = (cb > 261120) ? (byte)255 : (byte)(cb >> 10);

					// replace /1024 with shift(-10) (speed optimization)
		            br = (cr > 261120) ? 255 : (cr >> 10);
		            bg = (cg > 261120) ? 255 : (cg >> 10);
		            bb = (cb > 261120) ? 255 : (cb >> 10);
	            } else {
					// sandwich top-layer, use 100% pass-thru background image
					// imgBmp_byt[pixOff + 2] = (byte)br;
					// imgBmp_byt[pixOff + 1] = (byte)bg;
					// imgBmp_byt[pixOff + 0] = (byte)bb;
	            }

				result_dat[bPixOff] = (br << 16) + (bg << 8) + bb;

				// pixOff += d; // advance foreground to next pixel
				bPixOff += 1; // advance background to next pixel
			}
			// rowOff += rowBytes; // advance foreground to next row

			// advance background to next row
			// bRowOff += w;
			bRowOff -= w; // background image is upside-down
		}
	}

	// Ghost version
	public void process3(int[] bg_dat, int[] ex_dat, int[] result_dat, int w, int h, int percent) {
		if(ex_dat == null || percent <= 0) {
			process3(bg_dat, result_dat, w, h);
			return;
		}

		// TODO: read w, h, d, rowBytes, and header size from bmp header
		// int d = 3;
		// int rowBytes = w * d;

		int i, j;
		// int rowOff;
		int bRowOff;

		// foreground image color
		int fr, fg, fb;

		// background image color
		int ba = 0, br, bg, bb;

		// example image color
		int er, eg, eb;

		int[] backing = getBackingColor_int(result_dat, w, h);

		final int percentInv = 100 - percent;

		// process image
		// rowOff = SnapOut.bmpHeadSz;
		// bRowOff = 0;
		bRowOff = (h - 1) * w; // background image is upside-down
		for(j = 0; j < h; j++) {
			// int pixOff = rowOff;
			int bPixOff = bRowOff;
			for(i = 0; i < w; i++) {
				// read example image pixel
				final int ex = ex_dat[bPixOff];
				er = ((ex & 0x00ff0000) >> 16);
				eg = ((ex & 0x0000ff00) >> 8);
				eb = (ex & 0x000000ff);

				if(percent < 100) {

					// read background image pixel
					final int dat = (bg_dat == null) ? 0xFF3264C8 : bg_dat[bPixOff]; // Ultimatte blue
					// final int dat = (bg_dat == null) ? 0xFF404040 : bg_dat[bPixOff]; // gray
					// final int dat = bg_dat[bPixOff]; // gray

					ba = ((dat & 0xff000000) >> 24);
					// required because java so doesn't provide unsigned types
					if(ba < 0) {
						ba += 256;
					}

					br = ((dat & 0x00ff0000) >> 16);
					bg = ((dat & 0x0000ff00) >> 8);
					bb = (dat & 0x000000ff);

		            if(ba > 64) { // arbitrary threshold
						// not Sandwich top-layer, use preview algorithm

						fr = ((result_dat[bPixOff] & 0x00ff0000) >> 16);
						fg = ((result_dat[bPixOff] & 0x0000ff00) >> 8);
						fb = (result_dat[bPixOff] & 0x000000ff);

						// int dist = SnapUtil.abs(backing[0] - fr) +
						//            SnapUtil.abs(backing[1] - fg) +
						//            SnapUtil.abs(backing[2] - fb);

						// remove function call (speed optimization)
						int dist = ((backing[0] > fr) ? (backing[0] - fr) : (fr - backing[0])) +
						           ((backing[1] > fg) ? (backing[1] - fg) : (fg - backing[1])) +
						           ((backing[2] > fb) ? (backing[2] - fb) : (fb - backing[2]));

						// int m = (T < dist) ? 0 : (T - dist) * 1024 / T;

						// replace *1024 with shift(10) (speed optimization)
						// int m = (T < dist) ? 0 : ((T - dist) << 10) / T;

						// replace *1024/192 with *5 (speed optimization)
						int m = (T < dist) ? 0 : (T - dist) * 5;

			            // int pr = fr * 1024 - m * backing[0]; if(pr < 0) pr = 0;
			            // int pg = fg * 1024 - m * backing[1]; if(pg < 0) pg = 0;
			            // int pb = fb * 1024 - m * backing[2]; if(pb < 0) pb = 0;

						// replace *1024 with shift(10) (speed optimization)
			            int pr = (fr << 10) - m * backing[0]; if(pr < 0) pr = 0;
			            int pg = (fg << 10) - m * backing[1]; if(pg < 0) pg = 0;
			            int pb = (fb << 10) - m * backing[2]; if(pb < 0) pb = 0;

			            int cr = pr + m * br;
			            int cg = pg + m * bg;
			            int cb = pb + m * bb;

			            // write composite in-place into background
			            // 255 * 1024 = 261120
			            // imgBmp_byt[pixOff + 2] = (cr > 261120) ? (byte)255 : (byte)(cr / 1024);
			            // imgBmp_byt[pixOff + 1] = (cg > 261120) ? (byte)255 : (byte)(cg / 1024);
			            // imgBmp_byt[pixOff + 0] = (cb > 261120) ? (byte)255 : (byte)(cb / 1024);

						// replace /1024 with shift(-10) (speed optimization)
			            // imgBmp_byt[pixOff + 2] = (cr > 261120) ? (byte)255 : (byte)(cr >> 10);
			            // imgBmp_byt[pixOff + 1] = (cg > 261120) ? (byte)255 : (byte)(cg >> 10);
			            // imgBmp_byt[pixOff + 0] = (cb > 261120) ? (byte)255 : (byte)(cb >> 10);

						// replace /1024 with shift(-10) (speed optimization)
			            br = (cr > 261120) ? 255 : (cr >> 10);
			            bg = (cg > 261120) ? 255 : (cg >> 10);
			            bb = (cb > 261120) ? 255 : (cb >> 10);
		            } else {
						// sandwich top-layer, use 100% pass-thru background image
						// imgBmp_byt[pixOff + 2] = (byte)br;
						// imgBmp_byt[pixOff + 1] = (byte)bg;
						// imgBmp_byt[pixOff + 0] = (byte)bb;
		            }

		            // mix calculated pixel value with example image pixel
					br = (percentInv * br + percent * er) / 100;
					bg = (percentInv * bg + percent * eg) / 100;
					bb = (percentInv * bb + percent * eb) / 100;
				} else {
					// example 100%
					// imgBmp_byt[pixOff + 2] = (byte)er;
					// imgBmp_byt[pixOff + 1] = (byte)eg;
					// imgBmp_byt[pixOff + 0] = (byte)eb;
					br = er; bg = eg; bb = eb;
				}
				result_dat[bPixOff] = (br << 16) + (bg << 8) + bb;

				// pixOff += d; // advance foreground to next pixel
				bPixOff += 1; // advance background to next pixel
			}
			// rowOff += rowBytes; // advance foreground to next row

			// advance background to next row
			// bRowOff += w;
			bRowOff -= w; // background image is upside-down
		}
	}

	// Normal version
	public void process4(int[] bg_dat, int[] result_dat, int w, int h) {
		int i, j;
		int bRowOff;

		// background image color
		int ba, rgb;

		bRowOff = (h - 1) * w; // background image is upside-down
		for(j = 0; j < h; j++) {
			int bPixOff = bRowOff;
			for(i = 0; i < w; i++) {
				final int dat = (bg_dat == null) ? 0xFF3264C8 : bg_dat[bPixOff]; // Ultimatte blue

				ba = ((dat & 0xff000000) >> 24);
				// required because java so doesn't provide unsigned types
				if(ba < 0) {
					ba += 256;
				}

				rgb = dat & 0x00ffffff;

				if(ba > 64){
					ba = ba>>1;

					result_dat[bPixOff] = (ba << 24) + rgb;
				}
				else
					result_dat[bPixOff] = (255 << 24) + rgb;

				bPixOff += 1; // advance background to next pixel
			}
			bRowOff -= w; // background image is upside-down
		}
	}

	// Ghost version
	public void process4(int[] bg_dat, int[] ex_dat, int[] result_dat, int w, int h, int percent) {
		if(ex_dat == null || percent <= 0) {
			process4(bg_dat, result_dat, w, h);
			return;
		}

		int i, j;
		// int rowOff;
		int bRowOff;

		// background image color
		int ba, br, bg, bb;

		// example image color
		int er, eg, eb;

		final int percentInv = 100 - percent;

		// process image
		// rowOff = SnapOut.bmpHeadSz;
		// bRowOff = 0;
		bRowOff = (h - 1) * w; // background image is upside-down
		for(j = 0; j < h; j++) {
			// int pixOff = rowOff;
			int bPixOff = bRowOff;
			for(i = 0; i < w; i++) {
				// read background image pixel
				final int dat = (bg_dat == null) ? 0xFF3264C8 : bg_dat[bPixOff]; // Ultimatte blue
				// final int dat = (bg_dat == null) ? 0xFF404040 : bg_dat[bPixOff]; // gray
				// final int dat = bg_dat[bPixOff]; // gray

				ba = ((dat & 0xff000000) >> 24);
				// required because java so doesn't provide unsigned types
				if(ba < 0) {
					ba += 256;
				}
				ba = ba>>1;

				br = ((dat & 0x00ff0000) >> 16);
				bg = ((dat & 0x0000ff00) >> 8);
				bb = (dat & 0x000000ff);

				if(ba > 64){
					// read example image pixel
					final int ex = ex_dat[bPixOff];
					er = ((ex & 0x00ff0000) >> 16);
					eg = ((ex & 0x0000ff00) >> 8);
					eb = (ex & 0x000000ff);

					if(percent < 100) {
			            // mix calculated pixel value with example image pixel
						br = (percentInv * br + percent * er) / 100;
						bg = (percentInv * bg + percent * eg) / 100;
						bb = (percentInv * bb + percent * eb) / 100;
					} else {
						br = er; bg = eg; bb = eb;
					}

					result_dat[bPixOff] = (ba << 24) + (br << 16) + (bg << 8) + bb;
				}
				else
					result_dat[bPixOff] = (255 << 24) + (br << 16) + (bg << 8) + bb;

				// pixOff += d; // advance foreground to next pixel
				bPixOff += 1; // advance background to next pixel
			}
			// rowOff += rowBytes; // advance foreground to next row

			// advance background to next row
			// bRowOff += w;
			bRowOff -= w; // background image is upside-down
		}
	}

	public void processBgForDirectVideoOverlay(int[] bg_dat) {
		if(bg_dat == null) {
			return;
		}
		int i;
		final int sz = bg_dat.length;

		// background image color
		int ba = 0, br, bg, bb;

		for(i = 0; i < sz; i++) {

			// read background image pixel
			final int dat = bg_dat[i];

			ba = ((dat & 0xff000000) >> 24);
			// required because java so doesn't provide unsigned types
			if(ba < 0) {
				ba += 256;
			}

			br = ((dat & 0x00ff0000) >> 16);
			bg = ((dat & 0x0000ff00) >> 8);
			bb = (dat & 0x000000ff);

			if(ba > 64) { // arbitrary threshold
				// normal backing where foreground takes prescident
				/*
				ba = 0;
				br = 0;
				bg = 0;
				bb = 0;
				*/

				bg_dat[i] = 0;
			} else {
				// top layer sandwich area
				/*
				ba = 255;
				*/

				bg_dat[i] = (255 << 24) + (br << 16) + (bg << 8) + bb;
			}

		}
	}

	public void Heibai(int[] result_dat, int w, int h) {
		int i, j;
		int bRowOff;

		// background image color
		int ba, br, bg, bb;

		bRowOff = 0;//(h - 1) * w; // background image is upside-down
		for(j = 0; j < h; j++) {
			int bPixOff = bRowOff;
			for(i = 0; i < w; i++) {
				final int dat = (result_dat == null) ? 0xFF3264C8 : result_dat[bPixOff]; // Ultimatte blue

				ba = ((dat & 0xff000000) >> 24);
				// required because java so doesn't provide unsigned types
				if(ba < 0) {
					ba += 256;
				}

				br = ((dat & 0x00ff0000) >> 16);
				bg = ((dat & 0x0000ff00) >> 8);
				bb = (dat & 0x000000ff);

				br = bg = bb = ( br + bg + bb ) / 3;

				result_dat[bPixOff] = (ba << 24) + (br << 16) + (bg << 8) + bb;

				bPixOff += 1; // advance background to next pixel
			}
			bRowOff += w; // background image is upside-down
		}
	}

	public void Fugu(int[] result_dat, int w, int h) {
		int i, j;
		int bRowOff;

		// background image color
		int ba, br, bg, bb;

		bRowOff = 0;//(h - 1) * w; // background image is upside-down
		for(j = 0; j < h; j++) {
			int bPixOff = bRowOff;
			for(i = 0; i < w; i++) {
				final int dat = (result_dat == null) ? 0xFF3264C8 : result_dat[bPixOff]; // Ultimatte blue

				ba = ((dat & 0xff000000) >> 24);
				// required because java so doesn't provide unsigned types
				if(ba < 0) {
					ba += 256;
				}

				br = ((dat & 0x00ff0000) >> 16);
				bg = ((dat & 0x0000ff00) >> 8);
				bb = (dat & 0x000000ff);

				br = bg = bb = ( br + bg + bb ) >> 3;

				br += br << 1;
				bg = bg << 1;

				if(br > 255)
					br = 255;
				if(bg > 255)
					bg = 255;

				result_dat[bPixOff] = (ba << 24) + (br << 16) + (bg << 8) + bb;

				bPixOff += 1; // advance background to next pixel
			}
			bRowOff += w; // background image is upside-down
		}
	}

	public void Bopu(int[] result_dat, int w, int h) {
		int i, j, m, n;
		int bRowOff;
		int width = 4;
		int height = 4;
		int centerW = width /2;
		int centerH = height /2;

		int dat;

		// background image color
		int br, bg, bb;
		int tr, tg, tb;

		double offset;
		double[][] weight = new double[height][width];

		int total = 0;
		int max = (int)Math.pow((Math.pow(centerH, 2) + Math.pow(centerW, 2)), 1);

		for(m = 0; m < height; m++)
			for(n = 0; n < width; n++)
			{
				offset = max - (int)Math.pow((Math.pow((m - centerH), 2) + Math.pow((n - centerW), 2)), 1);
				total += offset;
				weight[m][n] = offset;
			}

		for(m = 0; m < height; m++)
			for(n = 0; n < width; n++)
			{
				weight[m][n] = weight[m][n] / total;
			}

		bRowOff = 0; // background image is upside-down
		for(j = 0; j < h; j+=height) {
			int bPixOff = bRowOff;

			for(i = 0; i < w; i+=width) {
				int bRowOff2 = bPixOff;

				tr = tg = tb = 0;

				for(m = 0; m < height; m++){
					if(j + m >= h)
						break;

					int bPixOff2 = bRowOff2;

					for(n = 0; n < width; n++){

						if(i + n >= w)
							break;

						dat = (result_dat == null) ? 0xFF3264C8 : result_dat[bPixOff2];

						tr += 255 - ((dat & 0x00ff0000) >> 16);
						tg += 255 - ((dat & 0x0000ff00) >> 8);
						tb += 255 - (dat & 0x000000ff);

						bPixOff2 += 1;
					}

					bRowOff2 += w;
				}

				bRowOff2 = bPixOff;

				for(m = 0; m < height; m++){
					if(j + m >= h)
						break;

					int bPixOff2 = bRowOff2;

					for(n = 0; n < width; n++){

						if(i + n >= w)
							break;

						offset = weight[m][n];

						br = 255 - (int)(tr * offset);
						bg = 255 - (int)(tg * offset);
						bb = 255 - (int)(tb * offset);

						if(br < 0)
							br = 0;
						if(bg < 0)
							bg = 0;
						if(bb < 0)
							bb = 0;

						result_dat[bPixOff2] = (0xff << 24) + (br << 16) + (bg << 8) + bb;

						bPixOff2 += 1; // advance background to next pixel
					}

					bRowOff2 += w;
				}

				bPixOff += width; // advance background to next pixel
			}
			bRowOff += w * height;
		}
	}

	public void Nuanse(int[] result_dat, int w, int h) {
		if(result_dat == null)
			return;
		int bRowOff = 0;
		int bb, br, bg;
		for(int j = 0; j < h; j++) {
			int bPixOff = bRowOff;
			for(int i = 0; i < w; i++) {
				br = (result_dat[bPixOff]>> 16) & 0x000000ff;
				bg = (result_dat[bPixOff]>> 8) & 0x000000ff;
				bb = (result_dat[bPixOff]) & 0x000000ff;

				br += 30;
				bg += 2;
				bb -= 10;
				if(br > 255)
					br = 255;
				if(bg > 255)
					bg = 255;
				if(bb < 0)
					bb = 0;
				result_dat[bPixOff] = (0xff << 24) | ((br & 0xff) << 16) | ((bg & 0xff) << 8) | (bb & 0xff);
				bPixOff ++;
			}
			bRowOff += w;
		}
	}

	public void Manhua(int[] result_dat, int w, int h) {
		if(result_dat == null)
			return;
		int[] historgram = new int[256];
		int bb, br, bg;
		int bRowOff = 0;
		for(int j = 0; j < h; j++) {
			int bPixOff = bRowOff;
			for(int i = 0; i < w; i++) {
				br = (result_dat[bPixOff]>> 16) & 0x000000ff;
				bg = (result_dat[bPixOff]>> 8) & 0x000000ff;
				bb = (result_dat[bPixOff]) & 0x000000ff;
				result_dat[bPixOff] = (int)((double)br*0.3 + (double)bg*0.59 + (double)bb*0.11);
				historgram[result_dat[bPixOff]]++;
				bPixOff ++;
			}
			bRowOff += w;
		}
		for(int i=0; i<256; i++) {
			int total = 0;
			for(int n=-2; n<=2; n++) {
				int q = n+i;
				if(q<0) q = 0;
				else if(q>255) q = 255;
				total += historgram[q];
			}
			historgram[i] = (int)(total/5.0+0.5);
		}
		int sum = 0;
		int n = 0;//
		for(int i=255; i>=0; i--) {
			sum += historgram[i]*i;
			n += historgram[i];
		}
//        记t为前景与背景的分割阈值，前景点数占图像比例为w0， 平均灰度为u0；背景点数占图像比例为w1，平均灰度为u1。
//        则图像的总平均灰度为：u=w0*u0+w1*u1。
//        前景和背景图象的方差：g=w0*(u0-u)*(u0-u)+w1*(u1-u)*(u1-u)=w0*w1*(u0-u1)*(u0-u1),
		int value = 0;
		int n0 = 0, n1 = 0, cu0 = 0, cu1 = 0;
		double g = 0, gmax = -1.0, u0 = 0, u1 = 0;
		for(int t=0; t<255; t++) {
			n0 += historgram[t];
			if(n0 == 0)continue;
			n1 = n - n0;
			if(n1 == 0)break;
			cu0 += historgram[t]*t;
			u0 = cu0 / n0;
			cu1 = sum - cu0;
			u1 = cu1 / n1;
			g = ((double)n0*(double)n1*(u0-u1)*(u0-u1));
			if(g > gmax) {
				gmax = g;
				value = t;
			}
		}
		bRowOff = 0;
		for(int j = 0; j < h; j++) {
			int bPixOff = bRowOff;
			for(int i = 0; i < w; i++) {
				if(result_dat[bPixOff] > value) {
					result_dat[bPixOff] = 0XFFFFFFFF;
				} else {
					result_dat[bPixOff] = 0XFF000000;
				}
				bPixOff ++;
			}
			bRowOff += w;
		}
//		int i, j;
//		int bRowOff;
//
//		// background image color
//		int ba, br, bg, bb, tmp;
//
//		bRowOff = 0;//(h - 1) * w; // background image is upside-down
//		for(j = 0; j < h; j++) {
//			int bPixOff = bRowOff;
//			for(i = 0; i < w; i++) {
//				final int dat = (result_dat == null) ? 0xFF3264C8 : result_dat[bPixOff]; // Ultimatte blue
//
//				ba = ((dat & 0xff000000) >> 24);
//				// required because java so doesn't provide unsigned types
//				if(ba < 0) {
//					ba += 256;
//				}
//
//				br = ((dat & 0x00ff0000) >> 16);
//				bg = ((dat & 0x0000ff00) >> 8);
//				bb = (dat & 0x000000ff);
//
//				tmp = ( br + bg + bb ) / 3;
//
//				if(tmp > 128)
//					br = bg = bb = 255;
//				else
//					br = bg = bb = 0;
//
//				result_dat[bPixOff] = (ba << 24) + (br << 16) + (bg << 8) + bb;
//
//				bPixOff += 1; // advance background to next pixel
//			}
//			bRowOff += w; // background image is upside-down
//		}
	}

	public void Saomiao(int[] result_dat, int w, int h) {
		int i, j;
		int bRowOff;
		int offset = 2;

		// background image color
		int ba, br, bg, bb;

		bRowOff = (h - 1) * w; // background image is upside-down
		for(j = 0; j <= h; j+=offset) {
			int bPixOff = bRowOff;
			for(i = 0; i < w; i++) {
				final int dat = (result_dat == null) ? 0xFF3264C8 : result_dat[bPixOff]; // Ultimatte blue

				ba = ((dat & 0xff000000) >> 24);
				// required because java so doesn't provide unsigned types
				if(ba < 0) {
					ba += 256;
				}

				br = ((dat & 0x00ff0000) >> 16);
				bg = ((dat & 0x0000ff00) >> 8);
				bb = (dat & 0x000000ff);

				br += br >> 1;
				bg += bg >> 1;
				bb += bb >> 1;

				if(br > 255)
					br = 255;
				if(bg > 255)
					bg = 255;
				if(bb > 255)
					bb = 255;

				result_dat[bPixOff] = (ba << 24) + (br << 16) + (bg << 8) + bb;

				bPixOff += 1; // advance background to next pixel
			}
			bRowOff -= w * offset; // background image is upside-down
			if(bRowOff < w)
				return;
		}
	}

	public void Anjiao(int[] result_dat, int w, int h) {
		int i, j;
		int bRowOff;
		int centerX1 = 0, centerX2 = 0;
		int centerY1 = 0, centerY2 = 0;
		float mindis = 0, maxdis = 0, offsetdis = 0, dis = 0;
		double offset;
		int dat = 0;

		if(w > h)
		{
			centerX1 = centerY1 = centerY2 = h/2;
			centerX2 = w - centerX1;

			mindis = ((int)(Math.pow((w/2 - centerX1), 2) + Math.pow((0 - centerY1), 2)) + (int)(Math.pow((w/2 - centerX2), 2) + Math.pow((0 - centerY2), 2))) / 2;
		}
		else
		{
			centerY1 = centerX1 = centerX2 = w/2;
			centerY2 = h - centerY1;

			mindis = ((int)(Math.pow((0 - centerX1), 2) + Math.pow((h/2 - centerY1), 2)) + (int)(Math.pow((0 - centerX2), 2) + Math.pow((h/2 - centerY2), 2))) / 2;
		}

		maxdis = (int)(Math.pow((0 - centerX1), 2) + Math.pow((0 - centerY1), 2)) + (int)(Math.pow((0 - centerX2), 2) + Math.pow((0 - centerY2), 2));
		offsetdis = maxdis - mindis;

		// background image color
		int ba, br, bg, bb;

		bRowOff = 0;//(h - 1) * w; // background image is upside-down
		for(j = 0; j < h; j++) {
			int bPixOff = bRowOff;
			for(i = 0; i < w; i++) {
				dat = (result_dat == null) ? 0xFF3264C8 : result_dat[bPixOff]; // Ultimatte blue

				ba = ((dat & 0xff000000) >> 24);
				// required because java so doesn't provide unsigned types
				if(ba < 0) {
					ba += 256;
				}

				br = ((dat & 0x00ff0000) >> 16);
				bg = ((dat & 0x0000ff00) >> 8);
				bb = (dat & 0x000000ff);

				dis = (int)(Math.pow((i - centerX1), 2) + Math.pow((j - centerY1), 2)) + (int)(Math.pow((i - centerX2), 2) + Math.pow((j - centerY2), 2)) - mindis;
				if(dis > 0)
				{
					offset = (offsetdis - dis)/offsetdis;
					//offset = Math.pow(offset, 0.5);

					br = (int)(br * offset);
					bg = (int)(bg * offset);
					bb = (int)(bb * offset);

					result_dat[bPixOff] = (ba << 24) + (br << 16) + (bg << 8) + bb;
				}

				bPixOff += 1; // advance background to next pixel
			}
			bRowOff += w; // background image is upside-down
		}
	}
}
